﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace server.app
{
    public sealed class HeroManager
    {
        World _world = null;

        public HeroManager(World word)
        {
            _world = word;
        }

        public Dictionary<string, long> NewNVValue(string dHeroId, string factionId, comm.objst.SpaceLoc loc, string planKey = comm.objst.DPlan.DEFAULT_KEY)
        {
            var nvvalueDic = new Dictionary<string, long>();
            var nvalueDic = _world.DefineFile.GetAllNValue(comm.objst.NValueGroup.HERO, true);
            var dUnit = _world.DefineFile.GetHero(dHeroId);
            var plan = dUnit.GetPlan(planKey);
            foreach (var key in nvalueDic.Keys)
            {
                var nv = nvalueDic[key];
                nvvalueDic.Add(key, nv.Value);
                if (plan.DefNVValueDic.ContainsKey(key))
                {
                    nvvalueDic[key] = comm.objst.NValue.Parse(nv.Type, plan.DefNVValueDic[key]);
                }
            }

            nvvalueDic.TrySet(Const.NVALUE_HERO_FACTION_ID, factionId);
            nvvalueDic.TrySet(Const.NVALUE_HERO_STAR_ID, loc.StarId);
            nvvalueDic.TrySet(Const.NVALUE_HERO_AT_STAR_ID, loc.StarId);
            nvvalueDic.TrySet(Const.NVALUE_HERO_AT_SPACE_ID, loc.SpaceId);
            nvvalueDic.TrySet(Const.NVALUE_HERO_LOC_X, loc.LocX);
            nvvalueDic.TrySet(Const.NVALUE_HERO_LOC_Y, loc.LocX);
            return nvvalueDic;
        }

        #region FactionId
        public string GetFactionId(Object obj)
        {
            return obj.NValueManager.GetNVValue(Const.NVALUE_HERO_FACTION_ID).ToString();
        }
        public void SetFactionId(Object obj, string factionId)
        {
            obj.NValueManager.TrySetNVValue(Const.NVALUE_HERO_FACTION_ID, factionId);
        }
        #endregion

        #region AtStarId
        public string GetAtStarId(Object obj)
        {
            return obj.NValueManager.GetNVValue(Const.NVALUE_HERO_AT_STAR_ID).ToString();
        }
        public void SetAtStarId(Object obj, string starId)
        {
            obj.NValueManager.TrySetNVValue(Const.NVALUE_HERO_AT_STAR_ID, starId);
        }
        #endregion

        #region AtSpaceId
        public string GetAtSpaceId(Object obj)
        {
            return obj.NValueManager.GetNVValue(Const.NVALUE_HERO_AT_SPACE_ID).ToString();
        }
        public void SetAtSpaceId(Object obj, string spaceId)
        {
            obj.NValueManager.TrySetNVValue(Const.NVALUE_HERO_AT_SPACE_ID, spaceId);
        }
        #endregion

        #region Speed
        public void SetSpeed(Object obj, int speed)
        {
            obj.NValueManager.TrySetNVValue(Const.NVALUE_HERO_SPEED, speed);
        }
        public int GetSpeed(Object obj)
        {
            return (int)obj.NValueManager.GetNVValue(Const.NVALUE_HERO_SPEED);
        }
        #endregion

        #region Loc
        public void SetLoc(Object obj, int x, int y)
        {
            obj.NValueManager.SetAllNVValue(new Dictionary<string, long> { { Const.NVALUE_HERO_LOC_X, x }, { Const.NVALUE_HERO_LOC_Y, y } });
        }
        public int GetLocX(Object obj)
        {
            return (int)obj.NValueManager.GetNVValue(Const.NVALUE_HERO_LOC_X);
        }
        public int GetLocY(Object obj)
        {
            return (int)obj.NValueManager.GetNVValue(Const.NVALUE_HERO_LOC_Y);
        }
        #endregion

        public bool UpdateHero(comm.objst.TablePlayer tablePlayer)
        {
            return _world.DataManager.TablePlayer.UpdatePlayer(tablePlayer);
        }

        public string CreateHero(comm.objst.CreateHero createHero, string planKey = comm.objst.DPlan.DEFAULT_KEY)
        {
            return _world.DataManager.Call<string>(sqlx =>
            {
                sqlx.BeginTxn();
                var r = CreateHero(sqlx, createHero, planKey);
                if (r == comm.CodeStr.OK)
                {
                    sqlx.CommitTxn();
                }
                return r;
            });
        }
        public string CreateHero(SQLx sqlx, comm.objst.CreateHero createHero, string planKey = comm.objst.DPlan.DEFAULT_KEY)
        {
            createHero.Nickname = createHero.Nickname.Trim();
            if (createHero.Nickname.Length == 0)
            {
                return "nickname_must_not_empty";
            }
            if (_world.DataManager.TablePlayer.NicknameExists(createHero.Nickname))
            {
                return "nickname_exists";
            }
            var dHero = _world.DefineFile.GetHero(createHero.HeroId);
            var star = _world.StarManager.GetStar(createHero.StarId);
            if (dHero == null)
            {
                return "heroId:\"" + createHero.HeroId + "\" not found";
            }
            if (star == null)
            {
                return "starId:\"" + createHero.StarId + "\" not found";
            }
            var fac = star.GetFaction(createHero.FactionId);
            if (fac == null)
            {
                return "factionId:\"" + createHero.FactionId + "\" not found";
            }
            var loc = fac.GetNewHeroSpaceLoc();
            if (loc == null)
            {
                Console.WriteLine("factionId:" + createHero.FactionId + " GetNewHeroSpaceLoc() is null", comm.ConsoleColor.RED);

                return "factionId:" + createHero.FactionId + " GetNewHeroSpaceLoc() is null";
            }
            var player = new comm.objst.TablePlayer
            {
                UserId = createHero.UserId,
                PlayerId = comm.GUID.NewString(),
                DObjectId = createHero.HeroId,
                Nickname = createHero.Nickname,
                NValueDic = NewNVValue(createHero.HeroId, createHero.FactionId, loc),
            };

            if (!_world.BackpackManager.CreackBackpack(sqlx, player.PlayerId))
            {
                return "CreateBackpack err";
            }

            #region DefStateList
            foreach (var item in dHero.DefStateList)
            {
                if (_world.DefineFile.GetState(item.StateId) != null)
                {
                    player.StateList.Add(new comm.objst.State
                    {
                        StateId = item.StateId,
                        BeginTime = DateTime.Now,
                        Dur = item.Dur
                    });
                }
            }
            #endregion

            #region DefEquipDic
            var equipTypes = comm.objst.DItem.ExpandAllEquipType(dHero.CanEquipTypeList.ToArray());
            foreach (var equipType in equipTypes)
            {
                if (dHero.DefEquipDic.ContainsKey(equipType) && dHero.DefEquipDic[equipType] != "")
                {
                    var itemIds = _world.ItemManager.CreateItem(sqlx, player.PlayerId, new comm.objst.CreateItem
                    {
                        ItemId = dHero.DefEquipDic[equipType],
                        Count = 1
                    });
                    if (itemIds != null)
                    {
                        player.EquipDic.Add(equipType, itemIds[0]);
                    }
                }
            }
            #endregion

            #region DefItemList
            foreach (var item in dHero.DefItemList)
            {
                var itemIds = _world.ItemManager.CreateItem(sqlx, player.PlayerId, item);
                if (itemIds != null)
                {
                    _world.ItemManager.ItemToBackpack(sqlx, player.PlayerId, itemIds);
                }
            }
            #endregion

            #region DefUnitList
            foreach (var item in dHero.DefUnitList)
            {
                _world.UnitManager.CreateUnit(sqlx, player.PlayerId, item);
            }
            #endregion

            Console.WriteLine("CreatePlayer:" + comm.JsonSerializer.Serialize(player));

            if (_world.DataManager.TablePlayer.CreatePlayer(sqlx, player))
            {
                star.StatNewHero(player.PlayerId, createHero.FactionId);
                return comm.CodeStr.OK;
            }
            return comm.CodeStr.ERROR;
        }

        public comm.objst.TablePlayer GetHero(string playerId)
        {
            return _world.DataManager.TablePlayer.GetPlayer(playerId);
        }
        public comm.objst.TablePlayer[] GetAllHero(string userId)
        {
            return _world.DataManager.TablePlayer.GetAllPlayer(userId);
        }
    }
}
